/* *  
 * Copyright (C) 2004-2008 Mocha Almond Fudge AI, SIT KMUTT
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package jboard.ui;

import java.awt.Cursor;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

import jboard.model.BoardPosition;
import jboard.model.GameEngine;
import jboard.model.IBoardConstant;
import jboard.model.Move;
import jboard.model.Token;
import jboard.model.ai.AI;
import jboard.util.MoveUtil;
import jboard.util.Utilities;
import jboard.ui.BoardGUI;

/**
 * Controll the movement from player
 * 
 * @author -NoP-
 */
public class Handler implements IBoardConstant {
	
	/**
	 * Main part to controll the game loop
	 * 
	 * @author -NoP-
	 */
	private class InputHandler extends MouseAdapter {
        // You're allowed to move the mouse while pressed within the same square
        private int saved_x;
		private int saved_y;
		private Token selectedToken;

		/**
		 * Start player turn
		 */
		public void mousePressed(MouseEvent e) {
		    saved_x = (e.getX() - 1) / CELL_SIZE;
			saved_y = (e.getY() - 1) / CELL_SIZE;
			
			// Check which turn
			int currentTurn = Utilities.getCurrentTurn(isAITurn);
			
			// check whether it is that side token or not 
			if(currentBPS.peek(saved_x,saved_y) == currentTurn) {	
			    System.out.print("From : " + saved_x + "," + saved_y);
			    selectedToken = new Token(saved_x, saved_y);
				// Encapsulate check possible move algorithm
				calcMoveableCells(currentBPS, selectedToken);
			}
			
			// Paint moveable cell
			paintMoveableCell(moveableCellList.iterator());
		}
		
		public void mouseReleased(MouseEvent e) {
		    if(selectedToken == null) {
		        System.out.println("Non token selected");
		        return;
		    }
		    
		    // dispose all moveable cell then clear moveable cell list from last turn
		    clearMoveableCell(moveableCellList.iterator());
		    
			deselect();
			int x = (e.getX() - 1) / CELL_SIZE;
			int y = (e.getY() - 1) / CELL_SIZE;
			System.out.println(" To : " + x + "," + y);
			
			// Check which turn
			int currentColor = Utilities.getCurrentTurn(isAITurn);
			
			Token toMoveToken = new Token(x, y);
			if(MoveUtil.isValidMovement(currentBPS, selectedToken, toMoveToken)) {
				engine.getBoardGUI().log("Player move from  " + selectedToken, false);	
				engine.getBoardGUI().log(" To " + toMoveToken, true);
			    currentBPS = currentBPS.makeMove(new Move(selectedToken, toMoveToken), currentColor);
			    /** Detect eatting */
			    engine.eatting(toMoveToken, WHITE, currentBPS);
			    engine.renderGUI(currentBPS);
			    final int aiToken = Utilities.getNoToken(currentBPS, BLACK) ;
			    final int playerToken = Utilities.getNoToken(currentBPS, WHITE);
		    	System.out.println("Black : " + aiToken + " White : " + playerToken);
		    	engine.getBoardGUI().getTokenPanel().setPlayerScore(playerToken);
		    	engine.getBoardGUI().getTokenPanel().setAIScore(aiToken);
		    	engine.checkAvatarStatus(playerToken, aiToken);
			    /** Check status*/
			    if(engine.isGameFinish(currentBPS)) {
			        // freeze the game.
			        engine.freezeGame();
			        engine.showFinishGameMessage();
			        return;
			    }
			    selectedToken = null;	// clear prev source
			    System.out.println("Player pass turn");
			    isAITurn = Utilities.passTurn(isAITurn); // passturn
			} else {
			    System.out.println("Invalid movement");
			}
			
			/**AI section */
			if(isAITurn && hasAI) {
			    System.out.println("Now is AI turn...");
			    engine.getBoardGUI().setStatus("AI turn");
			    // Thinking process
			    currentBPS = ai.makeMove(currentBPS);
			    // get movement from given currentBPS 
			    Move aiMove = ai.getMoved();
			    System.out.println("DEBUG: AI " + aiMove); 
			    engine.getBoardGUI().log("AI " + aiMove, true);
			    /** Detect eatting */
			    engine.eatting(aiMove.getMoveToToken(), BLACK, currentBPS);		    
			    engine.renderGUI(currentBPS);	
			    final int aiToken = Utilities.getNoToken(currentBPS, BLACK) ;
			    final int playerToken = Utilities.getNoToken(currentBPS, WHITE);
		    	System.out.println("Black : " + aiToken + " White : " + playerToken);
		    	engine.getBoardGUI().getTokenPanel().setPlayerScore(playerToken);
		    	engine.getBoardGUI().getTokenPanel().setAIScore(aiToken);
		    	engine.checkAvatarStatus(playerToken, aiToken);
			    /** Check status*/
			    if(engine.isGameFinish(currentBPS)) {
			        // freeze the game.
			        engine.showFinishGameMessage();
			        engine.freezeGame();
			        return;
			    }
			    System.out.println("AI finish thinking... pass turn");
			    
			    isAITurn = Utilities.passTurn(isAITurn); // passturn
			    System.out.println("Now is Player turn");
			    engine.getBoardGUI().setStatus("Player turn");
			}
		}
	}
	
	/**
	 * Controll mouse hovering behaviour
	 * 
	 * @author -NoP-
	 */
	private class MotionHandler extends MouseMotionAdapter {
        public void mouseMoved(MouseEvent e) {
            int x = (e.getX() - 1) / CELL_SIZE;
			int y = (e.getY() - 1) / CELL_SIZE;
			
			// Check which turn
			int currentTurn = Utilities.getCurrentTurn(isAITurn);
			
			// Check only within boardPanel
			if(x >= 0 && x <= 7 && y >= 0 && y <= 7) {
			    if(currentBPS.peek(x, y) == currentTurn) {	// Black or white
			        floater.setLocation(x * CELL_SIZE, y * CELL_SIZE);
			        thePane.setCursor(new Cursor(Cursor.HAND_CURSOR));
			        floater.setVisible(true);
			    } else {
			        deselect();
			    }
			}
        }
    }
	
	/**
	 * Display moveable cell in game
	 *
	 * @author Vashira Ravipanich
	 */
	private class MoveableCell {
	    private JLabel mCell;
	    private int x, y; // position x y
	    
	    public MoveableCell(int x, int y) {
	        this.x = x;
	        this.y = y;
	    }
	    
	    public void display() {
	        this.mCell = ThemeFactory.createFloater();
	        mCell.setBounds(0, 0, CELL_SIZE, CELL_SIZE);
			thePane.add(mCell, new Integer(TEMP_LAYER));
			mCell.setLocation(this.x * CELL_SIZE, this.y * CELL_SIZE);
			mCell.setVisible(true);
	    }
	    
	    public void dispose() {
	        mCell.setVisible(false);
	    }
	}
	private AI ai;
	private BoardCell cell;
	private int color;
	private BoardPosition currentBPS;
	private GameEngine engine;	
	private JLabel floater;
	private boolean hasAI = true;		// Use in debug
	private boolean isAITurn = false;	// Indicate which turn
	
	private Vector moveableCellList;
	private InputHandler theInputHandler;
	private MotionHandler theMotionHandler;
	private JLayeredPane thePane;
	
	public Handler(JPanel boardPanel) {
        thePane = (JLayeredPane)boardPanel.getComponent(0);
		theMotionHandler = new MotionHandler();
		theInputHandler = new InputHandler();
		floater = new JLabel(new BoardCell(BoardCell.SELECT));
		floater.setVisible(false);
		floater.setBounds(0, 0, CELL_SIZE, CELL_SIZE);
		thePane.add(floater, new Integer(TEMP_LAYER));
		
		color = WHITE;
		moveableCellList = new Vector();
    }
    
    /**
     * Encapsulated detect collision algorithm
     * 
     * @param currentBPS
     * @param selectedToken
     */
    private void calcMoveableCells(BoardPosition currentBPS, Token selectedToken) {
        for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
			    // Vertical line
				if (x == selectedToken.getX()) {
					Token toMoveToken = new Token(x, y);
					if(MoveUtil.isValidMovement(currentBPS, selectedToken, toMoveToken)) {
						if (currentBPS.peek(x, y) == EMPTY) moveableCellList.add(new MoveableCell(x, y));
					}
				}
				// Horizontal line
				if (y == selectedToken.getY()) {
					Token toMoveToken = new Token(x, y);
					if(MoveUtil.isValidMovement(currentBPS, selectedToken, toMoveToken)) {
						if (currentBPS.peek(x, y) == EMPTY) moveableCellList.add(new MoveableCell(x, y));
					}
				}
			}
        }
    }
    
    /**
     * Dispose all moveable cell then clear moveable cell list from last turn
     *
     */
    public void clearMoveableCell(Iterator iterator) {
        while(iterator.hasNext()) {
		    MoveableCell mCell = (MoveableCell) iterator.next();
		    mCell.dispose();
		}
	    moveableCellList.clear();
    }
    
    public void deselect() {
		floater.setVisible(false);
		thePane.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
	}
    
	public InputHandler getInputHandler() {
		return theInputHandler;
	}
    
    public MotionHandler getMotionHandler() {
		return theMotionHandler;
	}
    
    /**
     * Handle event that make AI move first
     */
    public void moveAIFirst() {
        isAITurn = true;	
        System.out.println("Now is AI turn...");	
	    engine.getBoardGUI().setStatus("AI turn");
	    // Thinking process
	    currentBPS = ai.makeMove(currentBPS);
	    Move aiMove = ai.getMoved();
	    System.out.println("DEBUG: AI " + aiMove);
	    engine.getBoardGUI().log("AI " + aiMove, true);
	    
	    engine.eatting(aiMove.getMoveToToken(), BLACK, currentBPS);
	    engine.renderGUI(currentBPS);	
	    final int aiToken = Utilities.getNoToken(currentBPS, BLACK) ;
	    final int playerToken = Utilities.getNoToken(currentBPS, WHITE);
    	System.out.println("Black : " + aiToken + " White : " + playerToken);
    	engine.getBoardGUI().getTokenPanel().setPlayerScore(playerToken);
    	engine.getBoardGUI().getTokenPanel().setAIScore(aiToken);
    	engine.checkAvatarStatus(playerToken, aiToken);
	    /** Check status*/
	    if(engine.isGameFinish(currentBPS)) {
	        // freeze the game.
	        engine.showFinishGameMessage();
	        engine.freezeGame();
	    }
	    System.out.println("AI finish thinking... pass turn");
	    
	    isAITurn = Utilities.passTurn(isAITurn); // passturn
	    System.out.println("Now is Player turn");
	    engine.getBoardGUI().setStatus("Player turn");
    }
    
    /**
     * Paint MoveableCell
     * 
     * @param iterator
     */
    public void paintMoveableCell(Iterator iterator) {
        while(iterator.hasNext()) {
		    MoveableCell mCell = (MoveableCell) iterator.next();
		    mCell.display();
		}
    }
    
    public void setAI(AI ai) {
        this.ai = ai;
    }
	
    public void setCurrentBPS(BoardPosition currentBPS) {
        this.currentBPS = currentBPS;
    }

    public void setEngine(GameEngine engine) {
        this.engine = engine;
    }
}
